<?php
/**
 * PDO连接池
 */
declare(strict_types=1);

namespace Libraries\Connections;

use Libraries\Config;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Database\PDOProxy;

class PDOConn
{
    private static $arrPool = []; // 按名称，维护多个连接池
    const MYSQL_MASTER = 'master'; // 主库标识
    const MYSQL_SLAVE = 'slave'; // 从库标识

    /**
     * 取连接池
     * @param string $strName
     * @param bool $blnSetNx 如果不存在，尝试初始化
     * @return PDOPool|null
     */
    private static function init(string $strName, bool $blnSetNx = false): ?PDOPool
    {
        if (isset(self::$arrPool[$strName])) {
            return self::$arrPool[$strName];
        }
        if (!$blnSetNx) {
            return null;
        }
        $objConfig = null;
        $intSize = 0;
        $arrConfig = Config::get('mysql_' . $strName);
        $arrConfig || $arrConfig = Config::get('mysql');
        if (is_array($arrConfig)) {
            $objConfig = (new PDOConfig())
                ->withHost($arrConfig['host'] ?? '127.0.0.1')
                ->withPort($arrConfig['port'] ?? 3306)
                ->withDbname($arrConfig['dbname'] ?? 'mysql')
                ->withUsername($arrConfig['user'] ?? 'root')
                ->withPassword($arrConfig['password'] ?? 'root')
                ->withDriver(PDOConfig::DRIVER_MYSQL)
                ->withCharset($arrConfig['charset'] ?? 'utf8mb4');
            $intSize = intval($arrConfig['pool_size'] ?? 5);
        }
        if ($objConfig && $intSize > 0) {
            self::$arrPool[$strName] = new PDOPool($objConfig, $intSize);
            return self::$arrPool[$strName];
        }
        return null;
    }

    /**
     * 关闭连接池，仅在WorkerStop中使用
     * @param string $strName
     * @return void
     */
    public static function close(string $strName = ''): void
    {
        if (strlen($strName)) {
            $objPool = self::init($strName);
            $objPool && $objPool->close();
            unset(self::$arrPool[$strName]);
        } else {
            foreach (self::$arrPool as $strName => $objPool) {
                $objPool && $objPool->close();
                unset(self::$arrPool[$strName]);
            }
        }
    }

    /**
     * 获取一个连接
     * @param string $strName
     * @return PDOProxy|null
     */
    public static function get(string $strName = ''): ?PDOProxy
    {
        strlen($strName) || $strName = self::MYSQL_MASTER;
        $objPool = self::init($strName, true);
        return $objPool ? $objPool->get() : null;
    }

    /**
     * 归还一个连接，就算当前连接不可用，也要归还Null
     * @param PDOProxy|null $objConn
     * @param string $strName
     * @return void
     */
    public static function put(?PDOProxy $objConn, string $strName = ''): void
    {
        strlen($strName) || $strName = self::MYSQL_MASTER;
        $objPool = self::init($strName);
        $objPool && $objPool->put($objConn);
    }
}
